package com.staples.tc.queueController;

import static com.staples.tc.util.TCIConstants.ESB_XML_START;
import static com.staples.tc.util.TCIConstants.KEY_CCARDQ_CHANNEL;
import static com.staples.tc.util.TCIConstants.KEY_CCARDQ_HOST;
import static com.staples.tc.util.TCIConstants.KEY_CCARDQ_PORT;
import static com.staples.tc.util.TCIConstants.KEY_CCARDQ_QMGR;
import static com.staples.tc.util.TCIConstants.KEY_CCARDQ_QUEUE;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import com.ibm.mq.MQC;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.staples.tc.exception.CCardJobException;
import com.staples.tc.util.CCardJobUtil;
import com.staples.tc.util.TCIResourceBundle;

public class CCardQConnManager {
	
	private static final Logger logger = Logger.getLogger(CCardQConnManager.class);
	private static MQQueue ccardQ;
	private static MQQueueManager ccardQMgr;
	
	private void createCCardQConnection() throws CCardJobException {
		logger.debug("Entering createCCardQConnection() ....");
		if (ccardQMgr == null || ccardQ == null) {
			
			try {
				// CCard Queue Configuration
				String host = TCIResourceBundle.getProperty(KEY_CCARDQ_HOST);
				String manager = TCIResourceBundle.getProperty(KEY_CCARDQ_QMGR);
				int port = Integer.parseInt(TCIResourceBundle.getProperty(KEY_CCARDQ_PORT));
				String channel = TCIResourceBundle.getProperty(KEY_CCARDQ_CHANNEL);
				String queue = TCIResourceBundle.getProperty(KEY_CCARDQ_QUEUE);

				MQEnvironment.hostname = host; // host to connect to
				MQEnvironment.channel = channel; // the CASE-SENSITIVE name of the SVRCONN channel
				MQEnvironment.port=port;
													
				ccardQMgr = new MQQueueManager(manager);
				int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT
						| MQC.MQOO_INQUIRE;
				ccardQ = ccardQMgr.accessQueue(queue, openOptions);
				logger.info("Queue connection success : " + host);
			} catch (MQException mExp) {
				logger.error("MQException occured while getting Queue connection ..." + mExp.getMessage());
				throw new CCardJobException(mExp.getMessage(), mExp);
			} catch (Exception exp) {
				logger.error("Exception occured while getting Queue connection ..." + exp.getMessage());
				throw new CCardJobException(exp.getMessage(), exp);
			}
		}
		logger.debug("Exiting createCCardQConnection() ....");
	}

	public ArrayList<String> readAllCCardQMessages() throws CCardJobException {
		logger.debug("Entering readAllCCardQMessages() ....");

		String readMessage = null;
		ArrayList<String> cCardMessages = new ArrayList<String>();
		try {
			//Initialize Queue Connection
			this.createCCardQConnection();
			
			MQGetMessageOptions gmo = new MQGetMessageOptions(); // accept
			// * the defaults // same as MQGMO_DEFAULT // get the message off
			// the
			// * queue...

			int depth = ccardQ.getCurrentDepth();			
			logger.info("Current C-Card Queue  depth :" + depth);
			
			if (depth == 0) {
				return cCardMessages;
			}

			for (int x = 0; x < depth; x++) {
				try {
					MQMessage message = new MQMessage();
//					message.format = MQC.MQFMT_STRING; // Read as JMSTextMessage
					ccardQ.get(message, gmo);
					byte[] readmsg = new byte[message.getMessageLength()];
					message.readFully(readmsg);	
					readMessage= new String(readmsg);
					logger.debug("Input message :" + CCardJobUtil.stripWhiteSpaces(readMessage));
					
//					readMessage=message.readStringOfByteLength(message.getMessageLength());
					int startIndex = readMessage.indexOf("<v2:CreateSalesOrder");
					logger.debug("Xml Start index :" + startIndex);
					if (readMessage.contains(ESB_XML_START) && startIndex != 0) {
						logger.debug("Removing message header ....");
						readMessage = readMessage.substring(readMessage.indexOf(ESB_XML_START));
						logger.debug("String value of message after removing Junk chars :" + CCardJobUtil.stripWhiteSpaces(readMessage));
					}
					
					cCardMessages.add(readMessage);
					
					message.clearMessage();
				} catch (IOException e) {
					logger.error("IOException during GET: ", e);
					break;
				} catch (MQException e) {
					if (e.completionCode == 2
							&& e.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) {
						if (depth > 0) {
							logger.info("All messages read.");
						}
					} else {
						logger.error("IOException during GET: ", e);
					}
					break;
				}
			}
		} catch (MQException mqExp) {
			logger.error("MQException occured while reading from Queue ..." + mqExp.getMessage());
			throw new CCardJobException(mqExp.getMessage(), mqExp);
		} catch (Exception exp) {
			logger.error("Exception occured while reading from Queue ..." + exp.getMessage());
			throw new CCardJobException(exp.getMessage(), exp);
		} finally {
			this.closeAllQResources();
		}
		
		logger.debug("Exiting readAllCCardQMessages() ....");
		return cCardMessages;
	}
	
	public void writeCCardQMessage(String cCardMessage) throws CCardJobException {
		logger.debug("Entering CCARD writeMessage() ....");
		
		try {
			//Initialize Queue Connection
			this.createCCardQConnection();
			logger.info("Current CCARD Queue depth :" + ccardQ.getCurrentDepth());

			MQMessage qMsg = new MQMessage();
//			qMsg.write(cCardMessage.getBytes("UTF-8"));
			qMsg.writeString(cCardMessage.toString());

			// specify the message options...
			MQPutMessageOptions pmo = new MQPutMessageOptions(); // accept the
																	// //
																	// defaults,
																	// same as
																	// MQPMO_DEFAULT

			// put the message on the queue
			logger.debug("Sending message to the CCARD queue :" + CCardJobUtil.stripWhiteSpaces(cCardMessage));
			ccardQ.put(qMsg, pmo);
			logger.info("MESSAGE SENT SUCCESSFULLY >>>>>>>>>");
			logger.info("Current CCARD Queue depth After Writing Message :" + ccardQ.getCurrentDepth());
		} catch (MQException mqExp) {
			logger.error("MQException occured while writing into Queue ..." + mqExp.getMessage());
			throw new CCardJobException(mqExp.getMessage(), mqExp);
		} catch (Exception exp) {
			logger.error("Exception occured while writing into Queue ..." + exp.getMessage());
			throw new CCardJobException(exp.getMessage(), exp);
		} finally {
			this.closeAllQResources();
		}
		logger.debug("Exiting CCARD writeMessage() ....");
	}
	
	public void closeAllQResources() {
		try {
			if (ccardQ != null && ccardQ.isOpen()) {
				ccardQ.close();
				ccardQ = null;
			}
			if (ccardQMgr != null && ccardQMgr.isOpen()) {
				ccardQMgr.close();
				ccardQMgr = null;
			}
		} catch (Exception exp) {
			logger.error("Exception while closing MQ Resources ...", exp);
		}
	}
}
